package com.sherlockmen.common.utils;

import jakarta.annotation.Resource;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author: menhao
 * @description: redis工具类
 * @date: 2025-03-04 11:04
 **/
public class RedisUtils {

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    /**
     * 设置过期时间，单位s
     *
     * @param key     键
     * @param timeout 过期时间
     */
    public void expire(String key, long timeout) {
        expire(key, timeout, TimeUnit.SECONDS);
    }

    public void expire(String key, long timeout, TimeUnit timeUnit) {
        redisTemplate.expire(key, timeout, timeUnit);
    }

    /**
     * 判断缓存是否存在
     *
     * @param key 键
     * @return
     */
    public boolean hasKey(String key) {
        return redisTemplate.hasKey(key);
    }

    /**
     * 设置缓存
     *
     * @param key
     * @param value
     */
    public void set(String key, Object value) {
        redisTemplate.opsForValue().set(key, value);
    }

    /**
     * 自增1
     *
     * @param key
     * @return
     */
    public long incr(String key) {
        return redisTemplate.opsForValue().increment(key);
    }

    /**
     * 设置缓存
     *
     * @param key
     * @param value
     * @param time
     * @param timeUnit
     */
    public void set(String key, Object value, long time, TimeUnit timeUnit) {
        redisTemplate.opsForValue().set(key, value, time, timeUnit);
    }

    /**
     * 获取string类型属性值
     *
     * @param key
     * @return
     */
    public Object get(String key) {
        return redisTemplate.opsForValue().get(key);
    }

    public String getString(String key) {
        Object obj = redisTemplate.opsForValue().get(key);
        return obj == null ? "" : obj.toString();
    }

    /**
     * 删除缓存
     *
     * @param key 键
     * @return
     */
    public boolean del(String key) {
        return redisTemplate.delete(key);
    }

    /**
     * 判断缓存是否存在
     *
     * @param key     键
     * @param hashKey 哈希key
     * @return
     */
    public boolean hasKey(String key, String hashKey) {
        return redisTemplate.opsForHash().hasKey(key, hashKey);
    }

    /**
     * 设置hash类型缓存
     *
     * @param key     键
     * @param hashKey 哈希key
     * @param value   值
     */
    public void hset(String key, String hashKey, Object value) {
        redisTemplate.opsForHash().put(key, hashKey, value);
    }

    /**
     * 设置hash类型缓存
     *
     * @param key   键
     * @param field 属性
     * @param value 值
     * @return
     */
    public boolean hset(String key, String field, String value) {
        try {
            redisTemplate.opsForHash().put(key, field, value);
            return true;
        } catch (Exception e) {
            return false;
        }

    }

    /**
     * 设置hash类型缓存如果不存在
     *
     * @param key     键
     * @param hashKey 哈希key
     * @param value   值
     * @return
     */
    public Boolean hsetIfAbsent(String key, String hashKey, Object value) {
        return redisTemplate.opsForHash().putIfAbsent(key, hashKey, value);
    }

    /**
     * 设置hash类型缓存
     *
     * @param key 键
     * @param map 属性-值集合
     */
    public void hmset(String key, Map<String, Object> map) {
        redisTemplate.opsForHash().putAll(key, map);
    }

    /**
     * 删除hash类型缓存
     *
     * @param key      键
     * @param hashKeys 哈希key
     */
    public void hdel(String key, Object... hashKeys) {
        redisTemplate.opsForHash().delete(key, hashKeys);
    }

    /**
     * 获取hash类型属性值
     *
     * @param key     键
     * @param hashKey hashKey
     * @return
     */
    public String hget(String key, String hashKey) {
        Object obj = redisTemplate.opsForHash().get(key, hashKey);
        return obj == null ? "" : obj.toString();
    }

    /**
     * 获取hash类型键值对
     *
     * @param key 键
     * @return
     */
    public Map<String, Object> hmget(String key) {
        Map<Object, Object> map = redisTemplate.opsForHash().entries(key);
        if (map == null || map.isEmpty()) {
            return null;
        }
        Map<String, Object> map2 = new HashMap<>();
        for (Object k : map.keySet()) {
            map2.put(k.toString(), map.get(k));
        }
        return map2;
    }

    /**
     * 加锁
     *
     * @param key
     * @param value
     * @param timeout
     * @return
     */
    public boolean lock(String key, String value, int timeout) {
        // 尝试获取锁
        // 如果设置成功，表示获取锁成功
        // 如果设置失败，表示其他线程已经持有锁
        return Boolean.TRUE.equals(redisTemplate.opsForValue().setIfAbsent(key, value, timeout, TimeUnit.SECONDS));
    }

    /**
     * 释放锁
     *
     * @param key
     * @param value
     */
    public void unlock(String key, String value) {
        // 释放锁时，需要验证锁的拥有者是否是执行释放操作的线程
        Object currentValue = redisTemplate.opsForValue().get(key);
        if (currentValue != null && currentValue.toString().equals(value)) {
            // 验证通过，删除键释放锁
            redisTemplate.delete(key);
        }
    }

    /**
     * 将值 value 关联到 key ，并将 key 的过期时间设为 timeout
     *
     * @param key
     * @param value
     * @param timeout 过期时间
     * @param unit    时间单位, 天:TimeUnit.DAYS 小时:TimeUnit.HOURS 分钟:TimeUnit.MINUTES
     *                秒:TimeUnit.SECONDS 毫秒:TimeUnit.MILLISECONDS
     */
    public void setEx(String key, String value, long timeout, TimeUnit unit) {
        redisTemplate.opsForValue().set(key, value, timeout, unit);
    }

    /**
     * Hash类型自增1
     *
     * @param key   键
     * @param field 属性
     * @return
     */
    public long hincr(String key, String field) {
        return redisTemplate.opsForHash().increment(key, field, 1);
    }

    /**
     * 从左边放入
     *
     * @param key    键
     * @param values 值集合
     */
    public void leftPushAll(String key, List<Object> values) {
        redisTemplate.opsForList().leftPushAll(key, values);
    }

    /**
     * 从右边放入
     *
     * @param key    键
     * @param values 值集合
     */
    public void rightPushAll(String key, List<Object> values) {
        redisTemplate.opsForList().rightPushAll(key, values);
    }

    /**
     * 获取List类型缓存
     *
     * @param key 键
     * @return
     */
    public List<Object> lget(String key) {
        return redisTemplate.opsForList().range(key, 0, -1);
    }

}
